package land_packge;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import plant_package.PlantLib;
import utilities_package.Debug;
import utilities_package.Pair;


public class LandBase implements LandInterface {
	Map<String, Integer> mLivingPlants = new HashMap<String, Integer>();
	
	public Map<String, Integer> getLivingPlants()
	{
		return new HashMap<String, Integer>(mLivingPlants);
	}
	
	public Integer getLivingPlants(String plantName)
	{
		if (mLivingPlants.containsKey(plantName))
			return mLivingPlants.get(plantName);
		else
			return 0;
	}
	
	public Map<String, Integer> produceResource()  
	{
		Debug.pi_warning("LandInterface should not be used directly.");
		return null;
	}
	
	public void develop(Map<String, Integer> externalResourceDemand, Map<String, Integer> externalPlantDemand)
	{
		Map<String, Integer> externalResourceCost = new HashMap<String, Integer>();
		Map<String, Integer> externalPlantCost = new HashMap<String, Integer>();
		
		Map<String, Integer> resources = produceResource();
		Map<String, Integer> plants = getLivingPlants();
		for (String resource : externalResourceDemand.keySet())
		{
			if (!resources.containsKey(resource) || resources.get(resource) == 0)
				continue;
			
			externalResourceCost.put(resource, Math.min(externalResourceDemand.get(resource), resources.get(resource)));
			resources.put(resource, resources.get(resource) - externalResourceCost.get(resource));   
		}
		
		for (String plant : externalPlantDemand.keySet())
		{
			if (!plants.containsKey(plant) || plants.get(plant) == 0)
				continue;
			
			externalPlantCost.put(plant, Math.min(externalPlantDemand.get(plant), plants.get(plant)));
			plants.put(plant, plants.get(plant) - externalPlantCost.get(plant));   
		}
		
		/*
		 * Resource amount is formulated by ; min(myDemand, myPressure / totalPressure * resourceAmount)
		 * If myDemand * totalPressure <= myPressure * resourceAmount, the plant will certainly take enough resource.
		 */
		
		Map<String, Map<String, Integer> > resourceAssignment = new HashMap<String, Map<String, Integer> >();
		for (String plant : plants.keySet())
			resourceAssignment.put(plant, new HashMap<String, Integer>());
		
		for (String resource : resources.keySet())
		{
			int totalPressure = 0;
			int totalDemand = 0;
			LinkedList<Pair<Double, String> > weights = new LinkedList<Pair<Double, String> >();
			
			for (String plant : plants.keySet())
			{
				int myPressure = PlantLib.getPlant(plant).computeResourcePressure(plants.get(plant), resource);
				int myDemand = PlantLib.getPlant(plant).computeResourceDemand(plants.get(plant), resource);
				
				totalPressure += myPressure;
				totalDemand += myDemand;
				Debug.pi_assert(myPressure > 0);
				weights.add(new Pair<Double, String>(((double)myDemand / (double) myPressure), resource));
			}

			for (Pair<Double, String> pair : weights)
			{
				if (pair.first * totalPressure <= totalDemand)
				{
					String plant = pair.second;
					int myPressure = PlantLib.getPlant(plant).computeResourcePressure(plants.get(plant), resource);
					int myDemand = PlantLib.getPlant(plant).computeResourceDemand(plants.get(plant), resource);
					resourceAssignment.get(plant).put(resource, myDemand);
					totalDemand -= myDemand;
					totalPressure -= myPressure;
				} else
				{
					String plant = pair.second;
					int myPressure = PlantLib.getPlant(plant).computeResourcePressure(plants.get(plant), resource);
					resourceAssignment.get(plant).put(resource, Double.valueOf((double) myPressure * (double) totalDemand / (double) totalPressure).intValue());
				}
			}
		}
		
		mLivingPlants.clear();
		for (String plant : plants.keySet())
		{
			int count = PlantLib.getPlant(plant).computeLivingCount(plants.get(plant), resourceAssignment.get(plant));
			if (count > 0)
				mLivingPlants.put(plant, count);
		}
	}
}
